﻿using System;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Windows.Forms.Calendar;

namespace SportManager
{
    public partial class MainForm : Form
    {
        enum CalendarMode
        {
            MONTH_MODE = 0,
            WEEK_MODE,
            DAY_MODE
        }

        enum CalendarItemType
        {
            TRAINING = 0,
            ANTROPOMETRIC
        }

        private CalendarMode CurrentCalendarMode;
        private const int MinimumDaysInWeekView = 4;
        private const int MaximumDaysInWeekView = 8;
        private const int DaysInWeek = 7;
        private const int MaximumViewDays = 42;

        private void InitializeCalendars()
        {
            mainCalendar.FirstDayOfWeek  = DayOfWeek.Monday;
            mainCalendar.MaximumViewDays = MaximumViewDays;

            monthView1.MonthTitleColor            = monthView1.MonthTitleColorInactive = CalendarColorTable.FromHex("#C2DAFC");
            monthView1.ArrowsColor                = CalendarColorTable.FromHex("#77A1D3");
            monthView1.DaySelectedBackgroundColor = CalendarColorTable.FromHex("#F4CC52");
            monthView1.DaySelectedTextColor       = monthView1.ForeColor;

            CurrentCalendarMode = CalendarMode.MONTH_MODE;
            toolStripButtonMonth.CheckState = CheckState.Checked;
            toolStripButtonWeek.CheckState  = CheckState.Unchecked;
            toolStripButtonDay.CheckState   = CheckState.Unchecked;

            ShowToday();
            PlaceItems();
        }

        private void calendar1_ItemCreated(object sender, CalendarItemCancelEventArgs e)
        {
            PlaceItems();
        }

        private void calendar1_LoadItems(object sender, CalendarLoadEventArgs e)
        {
            PlaceItems();
        }

        private bool IsNeedToShowCalendarItem(CalendarItem item)
        {
            return ((mainCalendar.Days[0].Date <= item.StartDate && mainCalendar.Days[mainCalendar.Days.Length - 1].Date >= item.EndDate)
                || (mainCalendar.Days.Length == 1)
            );
        }

        private void AddItemToCalendarIfNeed(CalendarItem item)
        {
            if (IsNeedToShowCalendarItem(item))
            {
                mainCalendar.Items.Add(item);
            }
        }

        private void monthView1_SelectionChanged(object sender, EventArgs e)
        {
            if ((monthView1.SelectionEnd - monthView1.SelectionStart).Days >= mainCalendar.MaximumViewDays)
            {
                return;
            }

            TimeSpan dayTimeSpan   = new TimeSpan(MinimumDaysInWeekView, 0, 0, 0);
            TimeSpan monthTimeSpan = new TimeSpan(MaximumDaysInWeekView, 0, 0, 0);
            mainCalendar.SetViewRange(monthView1.SelectionStart, monthView1.SelectionEnd);
            if (((monthView1.SelectionEnd.Subtract(monthView1.SelectionStart)) <= monthTimeSpan)
                && ((monthView1.SelectionEnd.Subtract(monthView1.SelectionStart)) >= dayTimeSpan)
              )
            {
                toolStripButtonMonth.CheckState = toolStripButtonDay.CheckState = CheckState.Unchecked;
                toolStripButtonWeek.CheckState  = CheckState.Checked;
                CurrentCalendarMode = CalendarMode.WEEK_MODE;
            }
            else if ((monthView1.SelectionEnd.Subtract(monthView1.SelectionStart)) < dayTimeSpan)
            {
                toolStripButtonMonth.CheckState = toolStripButtonWeek.CheckState = CheckState.Unchecked;
                toolStripButtonDay.CheckState = CheckState.Checked;
                CurrentCalendarMode = CalendarMode.DAY_MODE;
            }
            else if ((monthView1.SelectionEnd.Subtract(monthView1.SelectionStart)) > monthTimeSpan)
            {
                toolStripButtonWeek.CheckState = toolStripButtonDay.CheckState = CheckState.Unchecked;
                toolStripButtonMonth.CheckState = CheckState.Checked;
                CurrentCalendarMode = CalendarMode.MONTH_MODE;
            }

            PlaceItems();
        }

        private void calendar1_ItemDeleted(object sender, CalendarItemEventArgs e)
        {
            CalendarItemType type = (CalendarItemType)e.Item.ItemType;
            switch (type)
            {
                case CalendarItemType.TRAINING:
                    {
                        Trainings.RemoveAt(Trainings.FindIndex(a => (a.Id == e.Item.ItemGuid)));
                        break;
                    }
                case CalendarItemType.ANTROPOMETRIC:
                    {
                        Antropometrics.RemoveAt(Antropometrics.FindIndex(a => (a.Id == e.Item.ItemGuid)));
                        break;
                    }
                default:
                    {
                        throw new Exception("Wrong calendar item type!");
                    }
            }
        }

        private void PlaceItems()
        {
            mainCalendar.Items.Clear();
            CalendarItem item;
            foreach (Training data in Trainings)
            {
                item = new CalendarItem(mainCalendar, data.StartDate, data.FinishDate, data.StartDate.ToShortTimeString()
                    , data.Id, (int)CalendarItemType.TRAINING
                );

                AddItemToCalendarIfNeed(item);
            }

            foreach (AntropometricalData data in Antropometrics)
            {
                item = new CalendarItem(mainCalendar, data.Date, data.Date.AddMinutes(1), "Замер"
                    , data.Id, (int)CalendarItemType.ANTROPOMETRIC
                );

                AddItemToCalendarIfNeed(item);
                item.ApplyColor(Color.Green);                
            }

            monthView1.SetSelectionRange(mainCalendar.Days[0].Date, mainCalendar.Days[mainCalendar.Days.Length - 1].Date);
            
            ///WorkAround: Bug of Calendar control: if press "Down" on the keyboard - calendar throw NullReference exception///
            if (mainCalendar.SelectedElementStart == null)
            {
                mainCalendar.SelectedElementStart = mainCalendar.SelectedElementEnd = mainCalendar.Days[0];
            }
            ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////

            ShowDateInToolbox();
        }

        private bool IsTrainingCreated(Training training)
        {
            return (training.Exercises.Count > 0);
        }

        private void OnTrainingDoubleClick(Guid guid)
        {
            Training training = Program.TrainingsKeeper.FindItemByGuid(guid);

            if (IsTrainingCreated(training))
            {
                EditTrainingDlg form = new EditTrainingDlg(training);
                if (form.ShowDialog() == DialogResult.OK)
                {
                    Trainings[Program.TrainingsKeeper.GetItemIndex(training.Id)] = form.training;                    
                }
            }
            else
            {
                TrainingWizard.AddTrainingWizard form = new TrainingWizard.AddTrainingWizard(training.StartDate, training.Id);
                if (form.ShowDialog() == DialogResult.OK)
                {
                    Trainings[Program.TrainingsKeeper.GetItemIndex(training.Id)] = form.training;
                }
            }

            Trainings.Sort(Training.CompareByDate);
            PlaceItems();
        }

        private void OnAntropometricDoubleClick(Guid guid)
        {
            ShowAntropometricDlg(Program.AntropometricKeeper.GetItemIndex(guid));
        }

        private void calendar1_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            CalendarItem selectedItem = mainCalendar.ItemAt(new Point(e.X, e.Y));
            if (selectedItem == null)
            {
                return;
            }

            CalendarItemType type = (CalendarItemType)selectedItem.ItemType;
            switch (type)
            {
                case CalendarItemType.TRAINING:
                    {
                        OnTrainingDoubleClick(selectedItem.ItemGuid);
                        break;
                    }

                case CalendarItemType.ANTROPOMETRIC:
                    {
                        OnAntropometricDoubleClick(selectedItem.ItemGuid);
                        break;
                    }
                default:
                    {
                        throw new Exception("Wrong calendar item type!");
                    }
            }
        }        

        private void calendar1_ItemCreating(object sender, CalendarItemCancelEventArgs e)
        {
            DateTime startDate = new DateTime(e.Item.Date.Year, e.Item.Date.Month, e.Item.Date.Day);
            Trainings.Add(new Training(startDate.Year, startDate.Month, startDate.Day, e.Item.ItemGuid));
            e.Item.Text = startDate.ToShortTimeString();
        }

        private void toolStripButton2_Click(object sender, EventArgs e)
        {
            if (mainCalendar.SelectedElementStart != null)
            {
                mainCalendar.SetViewRange(mainCalendar.SelectedElementStart.Date, mainCalendar.SelectedElementStart.Date);
            }
            else if (monthView1.SelectionStart != new DateTime())
            {
                mainCalendar.SetViewRange(monthView1.SelectionStart, monthView1.SelectionStart);
            }
            else
            {
                mainCalendar.SetViewRange(DateTime.Today, DateTime.Today);
            }

            toolStripButtonWeek.CheckState = toolStripButtonMonth.CheckState = CheckState.Unchecked;
            toolStripButtonDay.CheckState = CheckState.Checked;
            CurrentCalendarMode = CalendarMode.DAY_MODE;

            PlaceItems();
        }

        private void toolStripButton3_Click(object sender, EventArgs e)
        {
            DateTime beginOfWeek;
            /*if (mainCalendar.SelectedElementStart != null)
            {
                beginOfWeek = mainCalendar.SelectedElementStart.Date;
            }
            else */if (monthView1.SelectionStart != new DateTime())
            {
                beginOfWeek = monthView1.SelectionStart;
            }
            else
            {
                beginOfWeek = DateTime.Today;
            }

            while (beginOfWeek.DayOfWeek != mainCalendar.FirstDayOfWeek)
            {
                beginOfWeek = beginOfWeek.AddDays(-1);
            }

            DateTime endOfWeek = beginOfWeek.AddDays(DaysInWeek - 1);
            mainCalendar.SetViewRange(beginOfWeek, endOfWeek);

            toolStripButtonDay.CheckState = toolStripButtonMonth.CheckState = CheckState.Unchecked;
            toolStripButtonWeek.CheckState = CheckState.Checked;
            CurrentCalendarMode = CalendarMode.WEEK_MODE;

            PlaceItems();
        }

        private void toolStripButton4_Click(object sender, EventArgs e)
        {
            DateTime selected;
            /*if (mainCalendar.SelectedElementStart != null)
            {
                selected = mainCalendar.SelectedElementStart.Date;
            }
            else */if (monthView1.SelectionStart != new DateTime())
            {
                selected = monthView1.SelectionStart;
            }
            else
            {
                selected = DateTime.Today;
            }

            DateTime firstMonthDay = new DateTime(selected.Year, selected.Month, 1);
            DateTime lastMonthDay = new DateTime(selected.Year, selected.Month, DateTime.DaysInMonth(selected.Year, selected.Month));
            mainCalendar.SetViewRange(firstMonthDay, lastMonthDay);

            toolStripButtonMonth.CheckState = CheckState.Checked;
            toolStripButtonDay.CheckState = toolStripButtonWeek.CheckState = CheckState.Unchecked;
            CurrentCalendarMode = CalendarMode.MONTH_MODE;

            PlaceItems();
        }

        private void MoveTraining(CalendarItem calendarItem)
        {
            Training moovingTraining = Program.TrainingsKeeper.FindItemByGuid(calendarItem.ItemGuid);
            switch (CurrentCalendarMode)
            {
                case CalendarMode.MONTH_MODE:
                    {
                        moovingTraining.StartDate = new DateTime(calendarItem.StartDate.Year, calendarItem.StartDate.Month
                            , calendarItem.StartDate.Day, moovingTraining.StartDate.Hour, moovingTraining.StartDate.Minute
                            , moovingTraining.StartDate.Second, moovingTraining.StartDate.Millisecond
                        );

                        moovingTraining.FinishDate = new DateTime(calendarItem.StartDate.Year, calendarItem.StartDate.Month
                            , calendarItem.StartDate.Day, moovingTraining.FinishDate.Hour, moovingTraining.FinishDate.Minute
                            , moovingTraining.FinishDate.Second, moovingTraining.FinishDate.Millisecond
                        );

                        break;
                    }
                case CalendarMode.WEEK_MODE:
                case CalendarMode.DAY_MODE:
                    {
                        moovingTraining.StartDate = calendarItem.StartDate;
                        moovingTraining.FinishDate = calendarItem.EndDate;
                        break;
                    }
                default:
                    throw new Exception("Unknown CalendarMode");
            }
        }

        private void MoveAntropometric(CalendarItem calendarItem)
        {
            AntropometricalData moovingData = Program.AntropometricKeeper.FindItemByGuid(calendarItem.ItemGuid);
            switch (CurrentCalendarMode)
            {
                case CalendarMode.MONTH_MODE:
                    {
                        moovingData.Date = new DateTime(calendarItem.StartDate.Year, calendarItem.StartDate.Month
                            , calendarItem.StartDate.Day, moovingData.Date.Hour, moovingData.Date.Minute
                            , moovingData.Date.Second, moovingData.Date.Millisecond
                        );

                        break;
                    }
                case CalendarMode.WEEK_MODE:
                case CalendarMode.DAY_MODE:
                    {
                        moovingData.Date = calendarItem.Date;
                        break;
                    }
                default:
                    throw new Exception("Unknown CalendarMode");
            }
        }

        private void calendar1_ItemDatesChanged(object sender, CalendarItemEventArgs e)
        {
            CalendarItemType type = (CalendarItemType)e.Item.ItemType;
            switch (type)
            {
                case CalendarItemType.TRAINING:
                    {
                        MoveTraining(e.Item);
                        break;
                    }
                case CalendarItemType.ANTROPOMETRIC:
                    {
                        MoveAntropometric(e.Item);
                        break;
                    }
                default:
                    {
                        throw new Exception("Wrong calendar item type!");
                    }
            }
        }        
    }
}